namespace Sudoku.SourceGeneration.Handlers;

internal static class ActionExtensionHandler
{
	public static void Generate(SourceProductionContext context)
	{
		var code = new List<string>();
		for (var i = 1; i <= 16; i++)
		{
			var values = Enumerable.Range(1, i).ToArray();
			var typeParameters = i == 1 ? "T" : string.Join(", ", from value in values select $"T{value}");
			var parameters = i == 1 ? "scoped ref T arg" : string.Join(", ", from value in values select $"scoped ref T{value} arg{value}");
			var parametersReadOnly = i == 1
				? "scoped ref readonly T arg"
				: string.Join(", ", from value in values select $"scoped ref readonly T{value} arg{value}");

			code.Add(
				$$"""
				/// <summary>
				/// Encapsulates a method that returns void but pass in a reference or a list of references.
				/// </summary>
				[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
				[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ActionExtensionHandler)}}", "{{Value}}")]
				public delegate void ActionRef<{{typeParameters}}>({{parameters}});

				/// <summary>
				/// Encapsulates a method that returns void but pass in a read-only reference or a list of read-only references.
				/// </summary>
				[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
				[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ActionExtensionHandler)}}", "{{Value}}")]
				public delegate void ActionRefReadOnly<{{typeParameters}}>({{parametersReadOnly}});

				/// <summary>
				/// Encapsulates a method that returns a <typeparamref name="TResult"/> and pass in a reference or a list of references.
				/// </summary>
				[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
				[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ActionExtensionHandler)}}", "{{Value}}")]
				public delegate TResult FuncRef<{{typeParameters}}, out TResult>({{parameters}});

				/// <summary>
				/// Encapsulates a method that returns a <typeparamref name="TResult"/> and pass in a read-only reference or a list of read-only references.
				/// </summary>
				[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
				[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(ActionExtensionHandler)}}", "{{Value}}")]
				public delegate TResult FuncRefReadOnly<{{typeParameters}}, out TResult>({{parametersReadOnly}});
				"""
			);
		}

		context.AddSource(
			"ActionExtensions.g.cs",
			$$"""
			{{Banner.AutoGenerated}}

			#nullable enable

			namespace System;

			{{string.Join("\r\n\r\n", code)}}
			"""
		);
	}
}
